use std::collections::HashMap;

use egui_snarl::{NodeId, Snarl};

use super::node::{Node, NodeTrait};

pub struct SnarlTreeNode {
    pub children:Vec<NodeId>,
    pub parent: Option<NodeId>
}

impl SnarlTreeNode {
    fn new() -> Self {
        Self {
            children:Vec::new(),
            parent:None
        }
    }
}

pub struct SnarlTree {
    pub nodes:HashMap<NodeId, SnarlTreeNode>
}

impl SnarlTree {
    fn new()->Self {
        Self {
            nodes: HashMap::new()
        }
    }
}

pub trait SnarlGenTree {
    fn gen_node_tree(&self)->SnarlTree;
}

impl SnarlGenTree for Snarl<Node> {
    fn gen_node_tree(&self)->SnarlTree {
        let mut tree = SnarlTree::new();

        let wires = self.wires();
        let compare_node = super::value::Value::Node;

        for (out_pin_id, in_pin_id) in wires {
            let Some(out_pin_node_info) = self.get_node(out_pin_id.node) else {continue;};
            let Some(in_pin_node_info) = self.get_node(in_pin_id.node) else {continue;};
            if out_pin_node_info.has_children() {
                let Some(output_data) = out_pin_node_info.get_output_info(out_pin_id.output) else {continue;};
                let Some(input_data) = in_pin_node_info.get_input_info(in_pin_id.input) else {continue;};
                if output_data.value.is_same_type(&compare_node) && input_data.value.is_same_type(&compare_node) {
                    let parent_node_info = tree.nodes.entry(out_pin_id.node).or_insert(SnarlTreeNode::new());
                    parent_node_info.children.push(in_pin_id.node);
                    let child_node_info = tree.nodes.entry(in_pin_id.node).or_insert(SnarlTreeNode::new());
                    child_node_info.parent = Some(out_pin_id.node);
                }
            }
        }

        for node in tree.nodes.values_mut() {
            node.children.sort_by(|a, b| {
                let a_y = self.get_node_info(*a).map(|info| info.pos.y).unwrap_or(f32::MAX);
                let b_y = self.get_node_info(*b).map(|info| info.pos.y).unwrap_or(f32::MAX);
                a_y.partial_cmp(&b_y).unwrap_or(std::cmp::Ordering::Equal)
            });
        }

        tree
    }
}
